<template>
  <div class="v-slider flex">
    <div
      class="v-slider_runway"
      :class="{ disabled }"
      @click="sliderClick"
      ref="slider"
    >
      <div ref="bar" class="v-slider-bar" :style="barStyle"></div>
      <div
        @mouseenter="mouseEnter"
        @mouseleave="mouseLeave"
        @mousedown="mouseDown"
        ref="button"
        class="v-slider-button"
        :style="buttonStyle"
      >
        <div class="v-slider_hover">{{ dispValue }}</div>
      </div>
    </div>
    <div v-if="inputNumber" class="v-slider_inpNum">
      <v-input-number
        v-model="inpNumValue"
        :min="min"
        :max="max"
        :precision="decimal"
        :disabled="disabled"
        @change="changeInpNum"
      ></v-input-number>
    </div>
  </div>
</template>
<script>
import VInputNumber from "../inputNumber/inputnumber.vue";
export default {
  components: {
    VInputNumber,
  },
  data() {
    return {
      barStyle: {},
      buttonStyle: {},
      targetValue: this.value,
      inpNumValue: this.value,
      dragging: false,
    };
  },
  props: {
    value: Number,
    disabled: {
      type: Boolean,
      default: false,
    },
    max: {
      type: Number,
      default: 100,
    },
    min: {
      type: Number,
      default: 0,
    },
    decimal: {
      type: Number,
      default: 0,
    },
    inputNumber: {
      type: Boolean,
      default: false,
    },
  },
  computed: {
    dispValue() {
      let targetValue = this.targetValue;
      this.min !== undefined &&
        targetValue < this.min &&
        (targetValue = this.min);
      this.max !== undefined &&
        targetValue > this.max &&
        (targetValue = this.max);
      return targetValue.toFixed(this.decimal);
    },
    ifDisabled() {
      return (
        this.disabled ||
        this.dispValue >= this.max ||
        this.dispValue <= this.min
      );
    },
  },
  created() {},
  mounted() {
    if (this.value !== undefined) {
      this.initPosition();
    }
  },
  methods: {
    sliderClick(event) {
      if (this.disabled) return;
      const moveLeft = this.moveLeft(event);
      this.resetSize();
      this.setStyle(moveLeft);
      this.setTargetValue(moveLeft / this.sliderSize);
      this.$emit("input", Number(this.dispValue));
      if (this.inputNumber) {
        this.inpNumValue = Number(this.dispValue);
      }
    },

    initPosition() {
      this.resetSize();
      this.setStyle(
        ((this.dispValue - this.min) / (this.max - this.min)) * this.sliderSize
      );
    },

    resetSize() {
      if (this.$refs.slider) {
        this.sliderSize = this.$refs.slider.clientWidth;
      }
    },

    setTargetValue(percent) {
      const targetValue = this.min + percent * (this.max - this.min);
      this.targetValue = targetValue;
    },

    setStyle(val) {
      this.barStyle = {
        width: this.dispStyle(val) + "px",
      };
      this.buttonStyle = {
        left: this.dispStyle(val) + "px",
      };
    },

    dispStyle(val) {
      let targetValue = val;
      this.min !== undefined && targetValue < 0 && (targetValue = 0);
      this.max !== undefined &&
        targetValue > this.sliderSize &&
        (targetValue = this.sliderSize);
      return targetValue;
    },

    moveLeft(event) {
      const sliderOffsetLeft = this.$refs.slider.getBoundingClientRect().left;
      return event.clientX - sliderOffsetLeft;
    },

    changeInpNum(val) {
      this.targetValue = val;
      this.initPosition();
      this.$emit("input", Number(this.dispValue));
    },

    mouseEnter() {},

    mouseLeave() {},

    mouseDown(event) {
      if (this.disabled) return;
      event.preventDefault();
      this.onDragStart(event);
      window.addEventListener("mousemove", this.onDragging);
      window.addEventListener("mouseup", this.onDragEnd);
      window.addEventListener("contextmenu", this.onDragEnd);
    },

    onDragStart(event) {
      this.dragging = true;
      this.startX = event.clientX;
      this.startPosition = this.moveLeft(event);
    },

    onDragEnd() {
      if (this.dragging) {
        setTimeout(() => {
          this.dragging = false;
        }, 0);
        this.$emit("input", Number(this.dispValue));
        if (this.inputNumber) {
          this.inpNumValue = Number(this.dispValue);
        }
        window.removeEventListener("mousemove", this.onDragging);
        window.removeEventListener("mouseup", this.onDragEnd);
        window.removeEventListener("contextmenu", this.onDragEnd);
      }
    },

    onDragging(event) {
      if (this.dragging) {
        let diff = 0;
        this.currentX = event.clientX;
        diff = this.currentX - this.startX;
        this.setStyle(diff + this.startPosition);
        this.setTargetValue((diff + this.startPosition) / this.sliderSize);
        if (this.inputNumber) {
          this.inpNumValue = Number(this.dispValue);
        }
      }
    },
  },
};
</script>
<style lang="less" scoped></style>
